/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.designtime.generator.entitydataconvertor.method;

import com.inspur.edp.bef.bizentity.GspBizEntityElement;
import com.inspur.edp.bff.designtime.generator.common.GenUtils;
import com.inspur.edp.bff.designtime.generator.entitydataconvertor.VMObjectDataConvertorGenContext;
import com.inspur.edp.caf.generator.baseInfo.ParameterInfo;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.method.ClassMethodGenerator;
import com.inspur.edp.caf.generator.utils.ExpressionUtils;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.entity.entity.IMultiLanguageData;
import com.inspur.edp.cef.entity.i18n.MultiLanguageInfo;
import com.inspur.edp.cef.generator.DotNetToJavaStringHelper;
import com.inspur.edp.formserver.viewmodel.GspViewModelElement;
import java.util.ArrayList;
import java.util.Arrays;
import lombok.var;
import org.eclipse.jdt.core.dom.ArrayAccess;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.CastExpression;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.InfixExpression.Operator;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;

public class MappingMultiLanguagePropsFromVoGenerator extends ClassMethodGenerator {

  private static final String ParamBeData = "beData";
  private static final String ParamVoData = "vmData";
  private static final String ParamMultiLangVoData = "vmMultiLanguageData";
  private static final String ParamMultiLangBeData = "_beMultiLanguageData";

  private VMObjectDataConvertorGenContext parentGenContext;

  public MappingMultiLanguagePropsFromVoGenerator(
      VMObjectDataConvertorGenContext parentGenContext) {
    this.parentGenContext = parentGenContext;
  }

  @Override
  protected ArrayList<Modifier.ModifierKeyword> getAccessModifiers() {
    return new ArrayList(Arrays.asList(
        new Modifier.ModifierKeyword[]{Modifier.ModifierKeyword.PROTECTED_KEYWORD}));
  }

  @Override
  protected boolean getIsOverride() {
    return true;
  }

  @Override
  protected String getMethodName() {
    return "mappingEntityDataMultiLanguagePropsFromVo";
  }

  @Override
  protected ArrayList<ParameterInfo> getParameterCollection() {
    ArrayList<ParameterInfo> list = new ArrayList();
    TypeInfo typeInfo = new TypeInfo("IEntityData");
    typeInfo.setTypePackageName("com.inspur.edp.cef.entity.entity");

    ParameterInfo paramBeData = new ParameterInfo();
    paramBeData.setParamType(typeInfo);
    paramBeData.setParamName(ParamBeData);

    list.add(paramBeData);
    ParameterInfo paramVoData = new ParameterInfo();
    paramVoData.setParamType(typeInfo);
    paramVoData.setParamName(ParamVoData);
    list.add(paramVoData);
    return list;
  }

  @Override
  protected TypeInfo getReturnType() {
    return new TypeInfo("void");
  }


  @Override
  protected Block buildMethodBody() {
    Block blockSyntax = getTypeAsBlock();

    for (IGspCommonField gspCommonField : parentGenContext.getVmObject().getContainElements()) {
      GspViewModelElement item = (GspViewModelElement) gspCommonField;
      if (item.getIsVirtual()) {
        continue;
      }
      if (DotNetToJavaStringHelper.isNullOrEmpty(item.getMapping().getTargetObjId()))
      //TODO 异常封装
      {
        throw new RuntimeException(
            "#GspBefError# 字段" + item.getCode() + " 的Mapping字段ID不允许为空#GspBefError#");
      }

      if (item.getMapping().getTargetMetadataId().equals(parentGenContext.getVmGeneratorContext()
          .getVm().getMapping().getTargetMetadataId()) == false) {
        continue;
      }

      Object tempVar = parentGenContext.getTargetObject()
          .findElement(item.getMapping().getTargetObjId());
      GspBizEntityElement entityElement = (GspBizEntityElement) (
          (tempVar instanceof GspBizEntityElement) ? tempVar : null);
      if (entityElement == null) {
        continue;
      }

      addElementMapBlock(item, entityElement, blockSyntax);
    }
    return blockSyntax;
  }

  private Block getTypeAsBlock() {
    Block block = ast.newBlock();
    //  IMultiLanguageData _beMultiData = (IMultiLanguageData) beData;
    //  IMultiLanguageData _vmMuttiData = (IMultiLanguageData) vmData;
    Statement beMultiLangDataStatement = this
        .getMultiLanguageDataStatement(ParamMultiLangBeData, ParamBeData);
    Statement voMultiLangDataStatement = this
        .getMultiLanguageDataStatement(ParamMultiLangVoData, ParamVoData);
    block.statements().add(beMultiLangDataStatement);
    block.statements().add(voMultiLangDataStatement);
    return block;
  }

  private Statement getMultiLanguageDataStatement(String varName, String paramName) {

    VariableDeclarationFragment frag = ast.newVariableDeclarationFragment();
    frag.setName(ast.newSimpleName(varName));
    CastExpression castStatement = ast.newCastExpression();
    castStatement
        .setType(ast.newSimpleType(ast.newName(IMultiLanguageData.class.getTypeName())));
    castStatement.setExpression(ast.newSimpleName(paramName));
    frag.setInitializer(castStatement);

    VariableDeclarationStatement statement = ast.newVariableDeclarationStatement(frag);
    statement
        .setType(ast.newSimpleType(ast.newName(IMultiLanguageData.class.getTypeName())));

    return statement;
  }

  private void addElementMapBlock(GspViewModelElement vmElement, GspBizEntityElement beElement,
      Block block) {
    if (vmElement.getIsUdt()) {
      return;
    }

    switch (vmElement.getObjectType()) {
      case None:
        if (vmElement.getObjectType() == GspElementObjectType.Association && vmElement
            .containRefElementNotFromAssoUdt()) {
          return;
        }
        if (vmElement.getIsMultiLanguage() && vmElement.isEnableMultiLanguageInput()) {
          this.addBasicElementMultiLanguageMapBlock(vmElement, beElement, block);
        }
        return;
      case DynamicProp:
      case Association:
      case Enum:
        return;
      default:
        throw new RuntimeException(
            "#GspBefError# 错误的类型" + vmElement.getObjectType().toString() + " #GspBefError# ");
    }
  }

  // if(_vmData.getMultiLanguageInfos().get(vmLalbelId)!=null)
  // _beData.getMultiLanguageInfos().put(beLabelId, _vmData.getMultiLanguageInfos().get(vmLalbelId).clone());
  private void addBasicElementMultiLanguageMapBlock(GspViewModelElement vmElement,
      GspBizEntityElement beElement,
      Block blockSyntax) {

    var voInfosMethodInvocation = ExpressionUtils
        .getMethodInvocation(ast, ParamMultiLangBeData, "getMultiLanguageInfos");
    var invocation = ExpressionUtils.getMethodInvocation(ast, voInfosMethodInvocation, "put");

    invocation.arguments().add(getMultiLanguageStringLateral(beElement.getLabelID()));

    var voInvocation = ExpressionUtils
        .getMethodInvocation(ast,
            getMultiLanguageInfosMethodInvocation(ParamMultiLangVoData, vmElement.getLabelID()),
            "clone");
    invocation.arguments().add(voInvocation);

    IfStatement ifStatement = ast.newIfStatement();
    InfixExpression expression = ast.newInfixExpression();

    expression.setLeftOperand(
        getMultiLanguageInfosMethodInvocation(ParamMultiLangVoData, vmElement.getLabelID()));
    expression.setRightOperand(ast.newNullLiteral());
    expression.setOperator(Operator.NOT_EQUALS);
    ifStatement.setExpression(expression);

    ifStatement.setThenStatement(ast.newExpressionStatement(invocation));

    blockSyntax.statements().add(ifStatement);
    addImport(MultiLanguageInfo.class.getTypeName());
  }

  private MethodInvocation getMultiLanguageInfosMethodInvocation(String para, String labelId) {
    var voInfosMethodInvocation = ExpressionUtils
        .getMethodInvocation(ast, para, "getMultiLanguageInfos");
    var voMultiLanguageInfos = ExpressionUtils
        .getMethodInvocation(ast, voInfosMethodInvocation, "get");
    voMultiLanguageInfos.arguments().add(getMultiLanguageStringLateral(labelId));
    return voMultiLanguageInfos;
  }

  private InfixExpression getMultiLanguageStringLateral(String labelId) {
    var caseExpression = ast.newInfixExpression();
    var labelIdLiteral = ast.newStringLiteral();
    labelIdLiteral.setLiteralValue(labelId);
    caseExpression.setLeftOperand(labelIdLiteral);
    caseExpression.setOperator(Operator.PLUS);
    caseExpression.setRightOperand(ast.newName("MultiLanguageInfo.MULTILANGUAGETOKEN"));
    return caseExpression;
  }
}
